/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package IRS.Logic;

import IRS.Domains.LocalResult;
import IRS.Domains.Phrase;
import IRS.Domains.Query;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 *
 * @author lin
 */
public class RocchioAlgorithm {

    private double a = 1;
    private double b = 0.75;
    private double g = 0.15;
    private int N = 10;
    private List<LocalResult> results;
    private Query query;
    HashMap<String, Double> r_vector_sum;
    HashMap<String, Double> nr_vector_sum;
    List<LocalResult> relevants;
    List<LocalResult> nonrelevants;
    HashMap<String, Integer> doc_frequency;

    public RocchioAlgorithm(Query old_query, List<LocalResult> results) {
        this.query = old_query;
        this.results = results;

        r_vector_sum = new HashMap<String, Double>();
        nr_vector_sum = new HashMap<String, Double>();
        relevants = new ArrayList<LocalResult>();
        nonrelevants = new ArrayList<LocalResult>();
        doc_frequency = new HashMap<String, Integer>();

        for (int i = 0; i < results.size(); i++) {
            LocalResult r = results.get(i);

            if (r.getRelevant() == true) {
                relevants.add(r);
            } else {
                nonrelevants.add(r);
            }
        }
    }

    /* a = alpha, b = beta, g = gamma */
    public void setParameters(double a, double b, double g) {
        this.a = a;
        this.b = b;
        this.g = g;
    }

    private void calculateDocFrequency(List<LocalResult> results) {
        for (int i = 0; i < results.size(); i++) {
            Map<String, Integer> terms = results.get(i).getTerms();

            Iterator<Map.Entry<String, Integer>> iter = terms.entrySet().iterator();

            while (iter.hasNext()) {
                Map.Entry<String, Integer> entry = (Map.Entry<String, Integer>) iter.next();

                String word = entry.getKey();

                if (!doc_frequency.containsKey(word)) {
                    doc_frequency.put(word, 1);
                } else {
                    doc_frequency.put(word, doc_frequency.get(word) + 1);
                }

            }
        }

    }

    private void calculateDocVector(List<LocalResult> results, Map<String, Double> vector_sum) {

        for (int i = 0; i < results.size(); i++) {
            Map<String, Integer> terms = results.get(i).getTerms();
            Iterator<Map.Entry<String, Integer>> iter = terms.entrySet().iterator();

            while (iter.hasNext()) {
                Map.Entry<String, Integer> entry = (Map.Entry<String, Integer>) iter.next();

                String term = entry.getKey();
                int term_frequency = entry.getValue();


                if (!doc_frequency.containsKey(term)) {
                    System.out.println(term);
                } else {
                    double weight = term_frequency * Math.log(N / doc_frequency.get(term));
                    double value = weight / results.size();
                    if (!vector_sum.containsKey(term)) {
                        vector_sum.put(term, 0.0);
                    }
                    vector_sum.put(term, vector_sum.get(term) + value);
                }
            }
        }
    }

    public Query execute() {

        calculateDocFrequency(relevants);
        calculateDocFrequency(nonrelevants);

        calculateDocVector(relevants, r_vector_sum);
        calculateDocVector(nonrelevants, nr_vector_sum);


        for (int i = 0; i < 2; i++) {
            String keyword = null;
            double max = 0;
            Iterator<Map.Entry<String, Double>> iter = r_vector_sum.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, Double> entry = (Map.Entry<String, Double>) iter.next();
                String key = entry.getKey();
                Double val = entry.getValue();
                if ((!query.contains(key)) && (!query.isStopword(key))) {
                    double weight = val;
                    if (nr_vector_sum.containsKey(key)) {
                        weight = weight - nr_vector_sum.get(key);
                    }

                    if (weight > max) {
                        max = weight;
                        keyword = key;
                        //System.out.println(key+" "+weight);
                    }
                }
            }
            query.addKeyword(keyword);
        }

        /* Form a phrase if possible */
        ArrayList<String> keywords = query.getKeywords();

        int[] keyword_ranks = new int[keywords.size()];
        ArrayList<Phrase> phrases = new ArrayList<Phrase>();

        for (int i = 0; i < keywords.size(); i++) {
            for (int j = 0; j < keywords.size(); j++) {
                if (i == j) {
                    continue;
                }
                phrases.add(new Phrase(keywords.get(i), keywords.get(j)));
            }
        }

        for (int i = 0; i < relevants.size(); i ++) {
            String[] title_terms = relevants.get(i).getTitle().split("[^a-z^A-Z^0-9]+");
                        
            for (int j = 0; j < title_terms.length; j ++) {
                for (int k = 0; k < keywords.size(); k ++) {
                    if(keywords.get(k).compareToIgnoreCase(title_terms[j]) == 0) {
                        keyword_ranks[k] ++;
                    }
                }
            }
            
            for (int j = 0; j < title_terms.length - 1; j++) {
                for (int k = 0; k < phrases.size(); k++) {
                    Phrase phrase = phrases.get(k);
                    if (title_terms[j].compareToIgnoreCase(phrase.getWord1()) == 0
                            && title_terms[j + 1].compareToIgnoreCase(phrase.getWord2()) == 0) {
                        phrase.addRank();
                        phrase.addRank();
                    } else if (title_terms[j].compareToIgnoreCase(phrase.getWord1()) == 0) {
                        phrase.reduceRank();
                    } else if (title_terms[j+1].compareToIgnoreCase(phrase.getWord2()) == 0) {
                        phrase.reduceRank();
                    }
                }
            }
        }

        ArrayList<Phrase> sorted_phrases = new ArrayList<Phrase>();
        while (phrases.size() > 0) {
            Phrase max_rank = phrases.get(0);
            for (int i = 1; i < phrases.size(); i++) {
                if (phrases.get(i).getRank() > max_rank.getRank()) {
                    max_rank = phrases.get(i);
                }
            }
            sorted_phrases.add(max_rank);
            phrases.remove(max_rank);
        }
 
        ArrayList<String> sorted_keywords = new ArrayList<String>();
        int[] sorted_ranks = new int[keywords.size()];
        
        ArrayList<Integer> ignores = new ArrayList<Integer>();
        for(int i = 0; i < keywords.size(); i ++) {
            
            int j = 0;
            while(ignores.contains(j))
                j ++;
            int max_rank_i = j;
            
            for(; j < keywords.size(); j ++) {
                if(ignores.contains(j))
                    continue;
                
                if (keyword_ranks[j] > keyword_ranks[max_rank_i]){
                    max_rank_i = j;
                }
            }
            
            sorted_keywords.add(keywords.get(max_rank_i));
            sorted_ranks[i] = keyword_ranks[max_rank_i];
            ignores.add(max_rank_i);
        }
        
        ArrayList<Phrase> max_cover = new ArrayList<Phrase>();
        ArrayList<String> temp_keywords = new ArrayList<String>();

        for (int i = 0; i < sorted_phrases.size(); i++) {
            Phrase phrase = sorted_phrases.get(i);
            if (!temp_keywords.contains(phrase.getWord1()) && !temp_keywords.contains(phrase.getWord2())
                    && sorted_phrases.get(i).getRank() > 0) {
                max_cover.add(phrase);
                temp_keywords.add(phrase.getWord1());
                temp_keywords.add(phrase.getWord2());
            }
        }
        
        ArrayList<String> final_keywords = new ArrayList<String>();
        for (int i = 0; i < sorted_keywords.size(); i ++){
            if (final_keywords.contains(sorted_keywords.get(i)))
                continue;
            
            for(int j = 0; j < max_cover.size(); j ++) {
                if (max_cover.get(j).hasWord(sorted_keywords.get(i))){
                    final_keywords.add(max_cover.get(j).getWord1());
                    final_keywords.add(max_cover.get(j).getWord2());
                    break;
                }
            }
            
            if(!final_keywords.contains(sorted_keywords.get(i)))
                final_keywords.add(sorted_keywords.get(i));
        }
        
        for(int i = 0; i < final_keywords.size(); i ++) {
            System.out.println(final_keywords.get(i));
        }
        
        return query;
    }
}
